#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/list.h>
#include<linux/cpumask.h>
#include<asm/local.h>

// #ifndef USE_FINDMOD 
static char * modname = NULL;
module_param(modname, charp, 0644);
MODULE_PARM_DESC(modname, "The name of module you want do clean or delete...\n");

static int __init rmmod_init(void)
{
    struct module *mod=NULL,*list_mod,*relate;
    int cpu;
    // 打印本模块的模块名和模块状态
    printk(KERN_ALERT"[insmod mod] name:%s state:%d\n", THIS_MODULE->name, THIS_MODULE->state);
	if (modname == NULL)
	{
	  printk(KERN_ALERT"[%s] need param modname=target\n", THIS_MODULE->name);
	  return -1;
	}
#ifndef USE_FINDMOD 
    // 遍历模块列表，查找target模块
    list_for_each_entry(list_mod, THIS_MODULE->list.prev, list)
    {
        //printk(KERN_ALERT"name:%s state:%d refcnt:%u ", mod->name,mod->state,module_refcount(mod));
        if (strcmp(list_mod->name, modname) == 0)
        {
			mod = list_mod;
		}
	}
	if (mod == NULL)
	{
	  printk(KERN_ALERT"[%s] module %s not found\n", THIS_MODULE->name, modname);
	  return -1;
	}
#else
	// 通过find_mod函数查找target模块
    if((mod = find_module(modname)) == NULL)
    {
        printk("[%s] module %s not found\n", THIS_MODULE->name, modname);
        return -1;
	}
#endif
	// 打印target的模块名、模块状态、引用计数
	printk(KERN_ALERT"[before]name:%s state:%d refcnt:%u ", mod->name, mod->state, module_refcount(mod));

	// 打印出所有依赖target的模块名
	/* for kernel version 2.x
	   if(!list_empty(&mod->modules_which_use_me))
	   {
	   list_for_each_entry(relate,&mod->modules_which_use_me, modules_which_use_me)
	   printk(KERN_ALERT"%s ",relate->name);
	   } */
	if (!list_empty(&mod->source_list))
	{
	  /*   打印出所有依赖target的模块名  */
	  list_for_each_entry(relate, &mod->source_list, source_list)
	  {
		printk("[relate]:%s\n", relate->name);
	  }
	}
	else
	{
	  printk(KERN_ALERT"used by NULL\n");
	}

	// 清除驱动的状态和引用计数
	// 修正驱动的状态为LIVE
	mod->state = MODULE_STATE_LIVE;
	// 清除驱动的引用计数
	for_each_possible_cpu(cpu)
	{
	  //local_set(__module_ref_addr(mod,cpu),0);  //kernel version 2.x
	  //local_set((local_t*)per_cpu_ptr(mod->refptr, cpu), 0);    //kernel version 3.x
	  //local_set((local_t*)per_cpu_ptr(&(mod->refcnt), cpu), 0);  //kernel version 4.x
	  atomic_set(&mod->refcnt, 1);
	}
	//atomic_set(&mod->refcnt, 1);
	// 再看看target的名称、状态、引用计数
	printk(KERN_ALERT"[after]name:%s state:%d refcnt:%u\n", mod->name, mod->state, module_refcount(mod));
    
    return 0;
}

static void __exit rmmod_exit(void)
{
    printk(KERN_ALERT"[rmmod mod] name:%s state:%d\n", THIS_MODULE->name, THIS_MODULE->state);
}

module_init(rmmod_init);
module_exit(rmmod_exit);

MODULE_AUTHOR("rocky");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("force remove module");

